package comtacti.native.internal.inlined;
import macrotools.Imports;
import comtacti.native.internal.inlined.Data;
import macrotools.MacroTools;
import haxe.Serializer;
import haxe.macro.Expr;
import haxe.macro.Context;
import macrotools.Map;
import neko.io.File;

/**
 * Build
 *   :	The build logic for InlinedHxcpp
 * 
 * @langversion		HaXe 2
 * @targets			macro
 * @author			Caue Waneck:<a href="mailto">waneck@gmail.com</a>
 * @since			2011-10-10
 */
class Build 
{
	private static var file = File.write("inlined_hxcpp.list", true);
	
	static function build():Array<Field> 
	{
		//by now we will only get the path of the class to inline content, and save it to a file
		//this file will be read by the install tool to determine which classes must have their parameters rebuilt
		var cls = Context.getLocalClass();
		var classPath = cls.toString();
		var cls = cls.get();
		var includes = [];
		var hxincludes = [];
		for (meta in cls.meta.get())
		{
			switch(meta.name)
			{
				case ":include", "include":
					includes.push(MacroTools.getString(meta.params[0]));
				case ":hxinclude", "hxinclude":
					var path = MacroTools.getPath(meta.params[0]).join(".");
					var type = Context.getType(path);
					if (type == null)
						Context.error("Type not found: " + path, meta.params[0].pos);
					type = Context.follow(type);
					
					var path = switch(type)
					{
						case TEnum(d,_): d.toString();
						case TInst(d,_): d.toString();
						default: Context.error("Unsupported type " + path, meta.params[0].pos);
					};
					
					hxincludes.push(path);
				default:
			}
		}
		
		var fields = Context.getBuildFields();
		var dataFields = [];
		
		for (field in fields)
		{
			switch(field.kind)
			{
				case FFun(func):
					var hasSpecial = false;
					
					function mapExpr(expr:Expr)
					{
						if (hasSpecial) return null;
						
						switch(expr.expr)
						{
							case ECall(e1, params):
								var mayident = MacroTools.getString(e1, true, false);
								if (mayident == "__cpp__")
									hasSpecial = true;
							default: Map.mapExpr(mapExpr, expr);
						}
						return null;
					}
					if (func.expr != null)
						Map.mapExpr(mapExpr, func.expr);
					
					if (hasSpecial)
					{
						var isInline = false;
						var acc = [];
						for (a in field.access)
						{
							if (a == AInline)
							{
								isInline = true;
							} else {
								acc.push(a);
							}
						}
						
						field.access = acc;
						dataFields.push( { name:field.name, isInline:isInline } );
					}
				default:
			}
		}
		
		if (dataFields.length == 0)
			Context.warning("No fields using special constructs were defined", Context.currentPos());
		
		var data:Data = {path:classPath.split("."), includes:includes, hxincludes:hxincludes, fields:dataFields};
		//use serialization so we can later have more complex information sent to the install tool
		file.writeString(Serializer.run(data));
		file.writeByte(0);
		file.flush();
		
		return fields;
	}
}